package yl.hs.bmipfull.service.finance.impl;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import yl.hs.bmipfull.daos.finance.IPurchaseReceiptFreightSettleDetailDao;
import yl.hs.bmipfull.daos.finance.IPurchaseReceiptFreightSettleMainDao;
import yl.hs.bmipfull.daos.finance.ISettleAdditionDao;
import yl.hs.bmipfull.daos.finance.ISettleOrderDao;
import yl.hs.bmipfull.daos.material.IPurchaseContractDao;
import yl.hs.bmipfull.daos.material.IPurchaseReceiptDao;
import yl.hs.bmipfull.daos.material.ISupplierDao;
import yl.hs.bmipfull.pojo.finance.*;
import yl.hs.bmipfull.pojo.material.PurchaseReceiptEntity;
import yl.hs.bmipfull.service.finance.IReceiptFreightSettleService;
import yl.hs.bmipfull.utils.CK;
import yl.hs.bmipfull.utils.HsApp;
import yl.hs.bmipfull.utils.SearchFilterEngine;
import yl.hs.bmipfull.utils.Tl;
import yl.hs.bmipfull.viewmodels.PageQuery;
import yl.hs.bmipfull.viewmodels.PageResult;
import yl.hs.bmipfull.viewmodels.SubmitModel;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;


@Service
public class ReceiptFreightSettleServiceImpl extends FinanceService implements IReceiptFreightSettleService {


    @Resource
    private IPurchaseReceiptDao purchaseReceiptDao;

    @Resource
    private ISettleOrderDao settleOrderDao;

    private IPurchaseReceiptFreightSettleMainDao mainDao;
    @Autowired
    public void setMainDao(IPurchaseReceiptFreightSettleMainDao mainDao) {
        this.mainDao = mainDao;
    }

    private IPurchaseReceiptFreightSettleDetailDao detailDao;

    @Autowired
    public void setDetailDao(IPurchaseReceiptFreightSettleDetailDao detailDao) {
        this.detailDao = detailDao;
    }

    private ISettleAdditionDao additionDao;

    @Autowired
    public void setAdditionDao(ISettleAdditionDao dao) {
        additionDao = dao;
    }

    private ISettleOrderDao orderDao;

    @Autowired
    public void setOrderDao(ISettleOrderDao dao) {
        orderDao = dao;
    }
    @Autowired
    ISupplierDao supplierdao;

    @Override
    public PageResult<Map<String, Object>> queryPage(PageQuery query, int rowNum, Integer page) throws ParseException {
        PageResult<Map<String, Object>> result;
        query.checkSortSides(PurchaseReceiptEntity.class);
        var filters = SearchFilterEngine.generateQueryList(query.getFilters(), ReceiptSettleMainEntity.class);
        List<Map<String, Object>> data = new ArrayList<>();
        if (rowNum > 0) {
            result = new PageResult<>(rowNum);
            query.getQuery().put("querySkip", (page - 1) * rowNum);
            query.getQuery().put("pageSize", rowNum);
            result.setRecords(mainDao.queryCountByCondition(query.getQuery(), filters));
            result.setPage(page);
            var list = mainDao.queryPage(query.getQuery(), filters);
            for (ReceiptFreightSettleMainEntity item : list) {
                data.add(Tl.toMap(item));
            }
        } else {
            var searchQuery = query.getQuery();
            if (query.getFilters() != null && query.getFilters().size() > 0) {
                var startTimeOpt = query.getFilters().stream().filter(t -> t.getField().equals("startTime")).findFirst();
                var endTimeOpt = query.getFilters().stream().filter(t -> t.getField().equals("endTime")).findFirst();
                startTimeOpt.ifPresent(queryFilter -> searchQuery.put("startTime", queryFilter.getSearchVal()));
                endTimeOpt.ifPresent(queryFilter -> searchQuery.put("endTime", queryFilter.getSearchVal()));
            }
            var orderList = mainDao.queryTempSettleOrders(searchQuery, filters);
            searchQuery.put("dutySN", HsApp.getSystemSet(CK.DriverDutySN));
            var carrierSns = orderList.stream().map(PurchaseReceiptEntity::getSupplierSN).distinct().toList();

            var carrierSettleLast = mainDao.queryCarrierSettleLast(searchQuery, filters);
            //var settlePayedList = settleMainDaoDao.queryContractReceiptList(searchQuery);//收款信息
            result = new PageResult<>(carrierSns.size() > 0 ? carrierSns.size() : 1);
            result.setRecords(carrierSns.size());
            result.setPage(page == null ? 1 : page);
            for (int i = 0; i < carrierSns.size(); i++) {
                ReceiptFreightSettleMainEntity item = new ReceiptFreightSettleMainEntity();
                var carrierSn = carrierSns.get(i);
                item.setCarrierSn(carrierSn);
                var supper =  supplierdao.findBySN(carrierSn);
                if(supper!=null){
                    item.setCarrierName(supper.getSupplierName());
                }
                item.setSn(String.format("CGJSTMP%s%s", Tl.getDateString(new Date(), "yyMMdd"), String.format("%d", i + 1)));
                var orders = orderList.stream().filter(t -> carrierSn.equals(t.getSupplierSN())).collect(toList());
                item.setSettleTime(new Date());
                Date min, max;
                var searchStart = query.getQuery().get("startTime");
                var searchEnd = query.getQuery().get("endTime");
                var dataParse = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
                if (searchStart == null || "".equals(searchStart)) {
                    if (orders.size() > 0) {
                        min = orders.stream().map(PurchaseReceiptEntity::getOutTime).filter(Objects::nonNull).min(Date::compareTo).get();
                    } else
                        min = new Date();
                } else {
                    min = dataParse.parse(searchStart.toString());
                }
                if (searchEnd == null || "".equals(searchEnd)) {
                    if (orders.size() > 0) {
                        max = orders.stream().map(PurchaseReceiptEntity::getOutTime).filter(Objects::nonNull).max(Date::compareTo).get();
                    } else
                        max = new Date();
                } else {
                    max = dataParse.parse(searchEnd.toString());
                }
                item.setStartTime(min);
                item.setEndTime(max);
                var lastSettle = carrierSettleLast.stream().filter(t -> carrierSn.equals(t.getCarrierSn())).findFirst();
                BigDecimal previousAmount = BigDecimal.ZERO,
                        totalPayedAmount = BigDecimal.ZERO,
                        currentPayedAmount = BigDecimal.ZERO,
                        totalAmount = BigDecimal.ZERO,
                        currentAmount = BigDecimal.ZERO,
                        unAAmount = BigDecimal.ZERO,//已审核未结算
                        unAmount = BigDecimal.ZERO;//未审核未结算
                int totalOrderCount = 0, currentOrderCount = 0, unAOrderCount = 0, unOrderCount = 0;

                if (lastSettle.isPresent()) {
                    var last = lastSettle.get();
                    previousAmount = last.getCurrentAmount();
                    totalPayedAmount = last.getTotalPayedAmount();
                    totalAmount = last.getTotalAmount();
                    totalOrderCount = last.getTotalOrderCount();
                }
                for (PurchaseReceiptEntity order : orders) {
                    if (order.getFreightState() == 1) {//已审核
                        if (order.getOutTime().compareTo(max) <= 0) {//参与结算
                            currentAmount = currentAmount.add(order.getFreightReviewAmount());
                            currentOrderCount++;
                        } else //不参与结算
                        {
                            unAAmount = unAAmount.add(order.getFreightReviewAmount() == null ? BigDecimal.ZERO : order.getFreightReviewAmount());
                            unAOrderCount++;
                        }
                    } else if (order.getState() >= 1 && order.getFreightState() == 0) {
                        unAmount = unAmount.add(order.getFreightReviewAmount() == null ? BigDecimal.ZERO : (order.getFreightReviewAmount()));
                        unOrderCount++;
                    }
                }
                item.setPreviousAmount(previousAmount);
                item.setCurrentAmount(currentAmount);
                item.setTotalAmount(totalAmount.add(currentAmount));
                item.setTotalPayedAmount(totalPayedAmount);
                item.setCurrentPayedAmount(currentPayedAmount);
                item.setCurrentOrderCount(currentOrderCount);
                item.setTotalOrderCount(totalOrderCount + currentOrderCount);
                item.setRemark("");
                item.setState((short) 1);
                item.setTags("");
                var dataMap = Tl.toMap(item);
                dataMap.put("unSettleApprovedAmount", unAAmount);
                dataMap.put("unSettleApprovedOrderCount", unAOrderCount);
                dataMap.put("unApprovedAmount", unAmount);
                dataMap.put("unApprovedOrderCount", unOrderCount);
                data.add(dataMap);
            }
        }
        result.setData(data);
        return result;
    }

    @Override
    public List<Map<String, Object>> queryTempSettleDetails(String carrierSn, String startDate, String endDate) throws ParseException {
        var start = parseTime(startDate, true);
        var end = parseTime(endDate, false);
        var data = detailDao.queryTempDetails(carrierSn, start, end);
        List<Map<String, Object>> list = new ArrayList<>();
        var groupData = data.stream().collect(
                Collectors.groupingBy(PurchaseReceiptEntity::getSupplierSN,
                        Collectors.groupingBy(PurchaseReceiptEntity::getSupplierName,
                                Collectors.groupingBy(PurchaseReceiptEntity::getRmSN,
                                        Collectors.groupingBy(PurchaseReceiptEntity::getRmName,
                                                Collectors.groupingBy(PurchaseReceiptEntity::getRmSpec,
                                                        Collectors.groupingBy(PurchaseReceiptEntity::getFreightReviewPrice, toList())))))));
        for (var supplierSN : groupData.keySet()) {
            var supplierSNGroup = groupData.get(supplierSN);
            for (var supplierName : supplierSNGroup.keySet()) {
                var supplierNameGroup = supplierSNGroup.get(supplierName);
                for (var rmSN : supplierNameGroup.keySet()) {
                    var rmSNGroup = supplierNameGroup.get(rmSN);
                    for (var rmName : rmSNGroup.keySet()) {
                        var rmNameGroup = rmSNGroup.get(rmName);
                        for (var rmSpec : rmNameGroup.keySet()) {
                            var rmSpecGroup = rmNameGroup.get(rmSpec);
                            for (var brand : rmSpecGroup.keySet()) {
                                ReceiptFreightSettleDetailEntity entity = new ReceiptFreightSettleDetailEntity();
                                var orders = rmSpecGroup.get(brand);
                                entity.setId(1L);
                                String minTime = "", maxTime = "";
                                var dateFormat = new SimpleDateFormat("yyyy-MM-dd");
                                var minDate = orders.stream().min(Comparator.comparing(PurchaseReceiptEntity::getOutTime));
                                var maxDate = orders.stream().max(Comparator.comparing(PurchaseReceiptEntity::getOutTime));
                                if (minDate.isPresent()) {
                                    minTime = dateFormat.format(minDate.get().getOutTime());
                                }
                                if (maxDate.isPresent()) {
                                    maxTime = dateFormat.format(maxDate.get().getOutTime());
                                }
                                entity.setTitle(String.format("%s 至 %s", minTime, maxTime));
                                entity.setSupplierSN(supplierSN);
                                entity.setSupplierName(supplierName);
                                entity.setRmSN(rmSN);
                                entity.setRmName(rmName);
                                entity.setRmSpec(rmSpec);
                                PurchaseReceiptEntity purchaseReceipt = orders.get(0);
                                entity.setFreightPrice(purchaseReceipt.getFreightReviewPrice());
                                entity.setOrderCount(orders.size());
                                var totalAmount = orders.stream().map(PurchaseReceiptEntity::getFreightReviewAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                                entity.setFreightAmount(totalAmount);
                                entity.setCarrierName(supplierName);
                                entity.setCarrierSn(supplierSN);
                                entity.setTotalWeight(orders.stream().map(PurchaseReceiptEntity::getNetWeight).reduce(BigDecimal.ZERO, BigDecimal::add));
                                var map = entity.toMap();
                                map.put("orderSnArray", orders.stream().map(PurchaseReceiptEntity::getSn).toList());
                                list.add(map);
                            }
                        }
                    }
                }
            }
        }
        return list;
    }

    @Override
    public Map<String, Object> querySettleDetailsBySettleSN(String settleSN) {
        Map<String, Object> result = new HashMap<>();
        List<ReceiptFreightSettleDetailEntity> details = detailDao.queryBySettleSN(settleSN);
        for (ReceiptFreightSettleDetailEntity detail : details) {
            detail.setTotalWeight(purchaseReceiptDao.getTotalReviewWeightBySettleDetailSn(detail.getSn()));
            String firstSn = settleOrderDao.getFirstPurchaseReceiptSn(detail.getSn());
            PurchaseReceiptEntity purchaseReceipt = purchaseReceiptDao.findBySN(firstSn);

            // 填充运费规则
            detail.setFreightPrice(purchaseReceipt.getFreightReviewPrice());
        }

        result.put("details", details);
        result.put("additions", additionDao.queryAdditionsBySettleSN(settleSN));
        return result;
    }

    @Override
    public Integer cancelSettle(String settleSN) {
        mainDao.changeOrderToSettled(1,settleSN);
        var result = mainDao.deleteBySettleSN(settleSN);
        result += detailDao.deleteBySettleSN(settleSN);
        result += additionDao.deleteBySettleSN(settleSN);
        result += orderDao.deleteBySettleSN(settleSN);
        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Integer saveSettle(SubmitModel model) throws Exception {
        var result = 0;
        var settleMain = new ReceiptFreightSettleMainEntity();
        Tl.getChangeLog(settleMain, model.getData());
        var settleSN = queryNewSN(settleMain.getClass());
        settleMain.setSn(settleSN);
        settleMain.setSettleTime(new Date());
        settleMain.setState((short) 1);
        settleMain.setPYFieldValue();
        settleMain.setOrganizationCode(getDepartSN());
        result = mainDao.insertNew(settleMain);
        if (result > 0) {
            var detailsObj = model.getData().get("details");
            if (detailsObj != null) {
                List<Map<String, Object>> detailList = (List<Map<String, Object>>) (detailsObj);
                if (detailList.size() > 0) {
                    for (Map<String, Object> detailMap : detailList) {
                        var orderSnObj = detailMap.get("orderSnArray");
                        var detailItem = new ReceiptFreightSettleDetailEntity();
                        var detailSN = queryNewSN(ReceiptFreightSettleDetailEntity.class);
                        Tl.getChangeLog(detailItem, detailMap);
                        detailItem.setSn(detailSN);
                        detailItem.setSettleSN(settleSN);
                        detailDao.insertNew(detailItem);
                        if (orderSnObj != null) {
                            List<String> orderSNList = (List<String>) orderSnObj;
                            if (orderSNList.size() > 0) {
                                for (String s : orderSNList) {
                                    var settleOrder = new SettleOrderEntity();
                                    settleOrder.setSettleSN(settleSN);
                                    settleOrder.setDetailSN(detailSN);
                                    settleOrder.setOrderSN(s);
                                    orderDao.insertNew(settleOrder);
                                }
                            }
                        }
                    }
                    mainDao.changeOrderToSettled(2,settleSN);
                }
            }
            var additionsObj = model.getData().get("additions");
            if (additionsObj != null) {
                List<Map<String, Object>> additionList = (List<Map<String, Object>>) additionsObj;
                if (additionList.size() > 0) {
                    for (Map<String, Object> map : additionList) {
                        var additionItem = new SettleAdditionEntity();
                        additionItem.setSn(queryNewSN(additionItem.getClass()));
                        Tl.getChangeLog(additionItem, map);
                        additionItem.setSettleSN(settleSN);
                        additionDao.insertNew(additionItem);
                    }
                }
            }
        }
        return result;
    }

    @Override
    public List<PurchaseReceiptEntity> querySettleOrdersBySettleSN(String settleSN) {
        return mainDao.querySettleOrdersBySettleSN(settleSN);
    }

//    @Override
//    public List<Map<String, Object>> purchaseFreightStatistics(Date startDate, Date endDate, String keywords) {
//        List<Map<String, Object>> list = Lists.newArrayList();
//
//        List<PurchaseFreightStatisticsVO> data = purchaseReceiptDao.purchaseFreightStatistics(startDate, endDate, keywords);
//
//        Map<String, List<PurchaseFreightStatisticsVO>> transTeamGroup = data.stream().collect(Collectors.groupingBy(PurchaseFreightStatisticsVO::getTransTeam));
//        for (String transTeamKey : transTeamGroup.keySet()) {
//            Map<String, Object> map = Maps.newLinkedHashMap();
//            map.put("transTeam", transTeamKey);
//            List<PurchaseFreightStatisticsVO> details = transTeamGroup.get(transTeamKey);
//            for (PurchaseFreightStatisticsVO target : details) {
//
//                // 设置运费规则
//                PurchaseContractEntity contract = contractDao.findBySN(target.getContractSn());
//                if (contract != null) {
//                    String freightRuleSN = contract.getFreightRuleSN();
//                    if (StringUtils.isNotEmpty(freightRuleSN)) {
//                        FreightRuleSetEntity freightRule = freightRuleSetDao.findBySN(freightRuleSN);
//                        if (freightRule != null) {
//                            List<FreightRuleSetDetailEntity> rules = freightRuleSetDetailDao.findByMainSn(freightRule.getSn());
//                            if (!CollectionUtils.isEmpty(rules)) {
//                                FreightRuleSetDetailEntity detail = rules.get(0);
//                                target.setPurchaseFreight(detail.getPrice());
//                            }
//                        }
//                    }
//                }
//                // 运费总价
//                BigDecimal freight = target.getPurchaseFreight() == null ? BigDecimal.ZERO : target.getPurchaseFreight();
//                target.setPurchaseFreightAmount(freight.multiply(target.getReviewWeightAmount()).setScale(2, BigDecimal.ROUND_HALF_UP));
//            }
//
//            map.put("reportList", transTeamGroup.get(transTeamKey));
//            list.add(map);
//        }
//        return list;
//    }

}
